package cn.iocoder.yudao.module.picturebook.service.bigplan;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

public class ReadingPlanAlgorithm {

    // 复习类型对应的间隔天数（索引 0 对应“不复习”，1 - 5 对应 1 - 5 次复习）
    private static final List<List<Integer>> REVIEW_INTERVALS = Arrays.asList(
            Collections.emptyList(), // 0: 不复习
            Arrays.asList(2),        // 1: 第 2 天复习
            Arrays.asList(2, 5),     // 2: 第 2、5 天复习
            Arrays.asList(2, 5, 8),  // 3: 第 2、5、8 天复习
            Arrays.asList(2, 5, 8, 16), // 4: 第 2、5、8、16 天复习
            Arrays.asList(2, 5, 8, 16, 31) // 5: 第 2、5、8、16、31 天复习
    );

    /**
     * 生成阅读计划（返回日期与书籍ID的映射）
     * @param bookIds       绘本ID列表
     * @param dailyNewCount 每天学几本新书
     * @param reviewType    复习类型（0-5）
     * @param startDate     计划开始日期
     * @return Map<日期, 当天所有要学的书籍ID>
     */
    public static Map<LocalDate, List<Long>> generateReadingPlan(
            List<Long> bookIds,
            int dailyNewCount,
            int reviewType,
            LocalDate startDate
    ) {
        // 参数校验
        if (bookIds == null) {
            throw new IllegalArgumentException("bookIds cannot be null");
        }
        if (startDate == null) {
            throw new IllegalArgumentException("startDate cannot be null");
        }
        if (dailyNewCount <= 0) {
            throw new IllegalArgumentException("dailyNewCount must be greater than 0");
        }
        if (reviewType < 0 || reviewType >= REVIEW_INTERVALS.size()) {
            throw new IllegalArgumentException("Invalid reviewType: " + reviewType);
        }

        // 1. 生成新书计划
        Map<LocalDate, List<Long>> newBooksPlan = generateNewBooksPlan(
                bookIds, dailyNewCount, startDate
        );

        // 2. 生成复习计划
        Map<LocalDate, List<Long>> reviewBooksPlan = generateReviewBooksPlan(
                newBooksPlan, reviewType
        );

        // 3. 合并新书和复习计划
        return mergePlans(newBooksPlan, reviewBooksPlan);
    }

    /**
     * 生成新书计划
     */
    private static Map<LocalDate, List<Long>> generateNewBooksPlan(
            List<Long> bookIds,
            int dailyNewCount,
            LocalDate startDate
    ) {
        Map<LocalDate, List<Long>> newBooksPlan = new TreeMap<>();
        int totalBooks = bookIds.size();
        int totalDays = (int) Math.ceil((double) totalBooks / dailyNewCount);

        for (int day = 0; day < totalDays; day++) {
            LocalDate currentDate = startDate.plusDays(day);
            int startIdx = day * dailyNewCount;
            int endIdx = Math.min(startIdx + dailyNewCount, totalBooks);

            List<Long> todayNewBooks = bookIds.subList(startIdx, endIdx);
            newBooksPlan.put(currentDate, todayNewBooks);
        }

        return newBooksPlan;
    }

    /**
     * 生成复习计划
     */
    private static Map<LocalDate, List<Long>> generateReviewBooksPlan(
            Map<LocalDate, List<Long>> newBooksPlan,
            int reviewType
    ) {
        Map<LocalDate, List<Long>> reviewBooksPlan = new TreeMap<>();
        if (reviewType == 0) return reviewBooksPlan; // 不复习

        List<Integer> reviewIntervals = REVIEW_INTERVALS.get(reviewType);

        // 遍历每天的新书，为每本书安排复习计划
        newBooksPlan.forEach((learnDate, bookIds) -> {
            bookIds.forEach(bookId -> {
                reviewIntervals.forEach(interval -> {
                    LocalDate reviewDate = learnDate.plusDays(interval - 1); // 注意：间隔-1（第2天实际是+1天）
                    reviewBooksPlan.computeIfAbsent(reviewDate, k -> new ArrayList<>())
                            .add(bookId);
                });
            });
        });

        return reviewBooksPlan;
    }

    /**
     * 合并新书计划和复习计划
     */
    private static Map<LocalDate, List<Long>> mergePlans(
            Map<LocalDate, List<Long>> newBooksPlan,
            Map<LocalDate, List<Long>> reviewBooksPlan
    ) {
        Map<LocalDate, List<Long>> mergedPlan = new TreeMap<>();

        // 先添加所有新书计划的日期
        newBooksPlan.forEach((date, newBooks) -> {
            List<Long> allBooks = new ArrayList<>(newBooks);
            // 添加当天的复习书（如果有）
            if (reviewBooksPlan.containsKey(date)) {
                allBooks.addAll(reviewBooksPlan.get(date));
            }
            mergedPlan.put(date, allBooks);
        });

        // 再添加只有复习书的日期（如果有）
        reviewBooksPlan.forEach((date, reviewBooks) -> {
            if (!mergedPlan.containsKey(date)) {
                mergedPlan.put(date, reviewBooks);
            }
        });

        return mergedPlan;
    }
}